package Account

import (
	"github.com/ethereum/go-ethereum/common"
	"Identity/ethdb/leveldb"
	"Identity/trie"
	"errors"
	"time"
)

var (
	// ErrAlreadyKnown is returned if the transactions is already contained
	// within the pool.
	ErrAlreadyKnown = errors.New("already known")

	// ErrInvalidSender is returned if the transaction contains an invalid signature.
	ErrInvalidASender = errors.New("invalid A sender")

	ErrInvalidBSender = errors.New("invalid B sender")

	ErrOversizedData = errors.New("oversized data")

	ErrOpenLeveldb = errors.New("open leveldb failed")

	ErrCreateTrieRoot = errors.New("create tree root failed")

	ErrTrieUninitialized = errors.New("trie uninitialized")

	ErrTriedbUninitialized = errors.New("trie Uninitialized")
)
const MaxQueueSize  = 1024
var  statsReportInterval  time.Duration = 60 * time.Second
var commitInternaval time.Duration = time.Hour

/* ============= LoveToken池 ============== */
type Head struct {

}
type LTPoolConfig struct {
	CommitInternval time.Duration
	ASignedTokensSize uint64
	BothSignedTokensSize uint64
}


func NewLTPool(config LTPoolConfig) *LTPool{
	pool := &LTPool{
		config:config,
		chainHeadCh:make(chan Head),
		errChan:make(chan error),
		BothSignedTokens:NewTokenQueue(config.BothSignedTokensSize),
	}

	err := pool.InitDB()
	if err != nil{
		panic(err)
	}

	return pool
}

type LTPool struct {
	config LTPoolConfig
	chainHeadCh chan Head
	errChan chan error

	// 每2小时提交一次 或者 队列满进行提交
	CommitToken2Tree chan int
	//每24小时提交一次
	SendTreeRoot2Block chan int

	//journal 交易日志

	// Token
	ReceiveTokenChan chan *LoveToken
	BothSignedTokens *TokenQueue

	triedb *trie.Database
	trie *trie.Trie
}



func (this * LTPool)Loop(){

	var (
		//每两个小时将token组合成树提交一次
		CommitTokenToTreeCycle = time.NewTicker(2 * time.Hour)
		SendTreeRoot2BlockCycle = time.NewTicker(24*time.Hour)

		// 报告交易池状态
		report = time.NewTicker(30 * time.Second)

	)

	defer CommitTokenToTreeCycle.Stop()
	defer SendTreeRoot2BlockCycle.Stop()
	defer report.Stop()

	for {
		select {
		case token := <-this.ReceiveTokenChan:
			this.validateToken(token)
			err := this.add(token)
		case <-CommitTokenToTreeCycle.C:
			this.AddAllTokenToTree()
			this.CommitTree()
		case <-SendTreeRoot2BlockCycle.C:

		case <-report.C:


		}
	}
}
func (this * LTPool)validateToken(token *LoveToken)error{
	//1.检查LoveToken大小
	if token.Size() > 1024 *32 {
		return ErrOversizedData
	}

	//2. 检查签名有效性
	ok , err , _ := token.VerfyASigend()
	if err!= nil || !ok{
		return ErrInvalidASender
	}
	ok , err , _ = token.VerifyBSigned()
	if err!= nil || !ok{
		return ErrInvalidBSender
	}

	return nil

}

func (this * LTPool)add (token * LoveToken) error {
	hash := token.Hash()
	_ ,exist := this.BothSignedTokens.GetIndexByTokenHash(hash)
	if exist{
		//该token已经存在
		return ErrAlreadyKnown
	}

	err := this.BothSignedTokens.Join(token)
	if err != nil{
		return err
	}

	return nil
}


func (this * LTPool)InitDB() (err error){

	if this.triedb == nil{
		diskdb,err   := leveldb.New("./dbFile",256,0,"tokenPool" ,false )
		if err!= nil{
			return ErrOpenLeveldb
		}

		db := trie.NewDatabase(diskdb)
		this.triedb = db
	}

	if this.trie ==nil{
		t, err := trie.New(common.Hash{},this.triedb )
		if err != nil{
			return ErrCreateTrieRoot
		}

		this.trie = t

	}

	return  nil
}


func (this * LTPool)AddTokenToTree(token * LoveToken) error{
	if this.trie != nil{
		err := this.trie.TryUpdate(token.Hash().Bytes(), token.EncodeToRLPBytes())
		if err != nil {
			return err
		}
	}else{
		return ErrTrieUninitialized
	}
	return nil
}

func (this * LTPool)CommitTree() error{
	root,err := this.trie.Commit(nil )

	if err != nil{
		return err
	}

	t,err := trie.New(root,this.triedb)
	if err != nil{
		return err
	}

	this.trie = t

	return nil
}


func ( this *LTPool)AddAllTokenToTree() error {
	for this.BothSignedTokens.Len() > 0{
		token, err := this.BothSignedTokens.outToken()
		if err != nil{
			continue
		}
		err = this.AddTokenToTree(token)
		if err != nil{
			continue
		}
	}
	return this.CommitTree()
}


//func (this * LTPool)upgrade(){
//	this.loveTokens.Join(this.requireBSignedLoveTokens.out)
//}
//// 停止接收交易
//func (this * LTPool)commitTree(){
//
//}
//// 报告pool 当前队列状态
//func (this * LTPool)status() (int,int,int ,int  ){
//	return this.requireBSignedLoveTokens.len,this.requireBSignedLoveTokens.limit, this.loveTokens.len,this.loveTokens.limit
//}
//func (this * LTPool)loop(){
//
//	var (
//		commitCycle = time.NewTicker(this.CommitInternval)
//		report  = time.NewTicker(statsReportInterval)
//	)
//
//	defer commitCycle.Stop()
//	defer report.Stop()
//	for   {
//		select {
//		// 订阅新区块头事件
//		case <- this.chainHeadCh:
//			fmt.Println("重新更新当前区块头")
//		case <- commitCycle.C:
//			this.commitTree()
//		case <- report.C:
//			fmt.Println(this.status())
//		case err :=<- this.errChan:
//			 log.Error(err)
//		default:
//
//		}
//	}
//
//}
